package org.kolonitsky.alexey.algorithm
{
    import org.kolonitsky.alexey.debug.DebugWrapper;
    import com.carlcalderon.arthropod.Debug;

    public class UintStateMachine
    {
        //---------------------------------------------------------------------
        //
        // Methods
        //
        //---------------------------------------------------------------------
        
        /**
         * 
         * 
         */
        public function setFlag(flag:uint):void
        {
            if (currentBitset.test(flag))
                return;
            
            currentBitset.set(flag);
            checkStates();
        }
        
        /**
         * 
         * 
         */
        public function clearFlag(flag:uint):void
        {
            if (!currentBitset.test(flag))
                return;
                
            currentBitset.clear(flag);
            checkStates();
        }
    
        /**
         *  Register new state and it callback
         *  
         *  @param state is set of flags  
         */ 
        public function registerState(state:uint, callback:Function):void
        {
            for (var i:int = 0; i < states.length && states[i].state != state; ) i++;
            if (i >= states.length)
            {
                states.push({state:state, callback:callback});
                DebugWrapper.info("add state: " + state + "\n      " + String(new UintBitset(state)), this);
            }
        }
        
        /**
         *  Remove registred state
         */ 
        public function removeState(state:uint):void
        {
            for (var i:int = 0; i < states.length && states[i].state != state; ) i++;
            if (i < states.length)
                states.splice(i, 1);
        }
        
        /**
         *  Check availability of state.
         */ 
        public function hasState(state:uint):Boolean
        {
            for (var i:int = 0; i < states.length && states[i].state != state; ) i++;
            return i < states.length;
        }

    
        //---------------------------------------------------------------------
        //
        // Private logic
        //
        //---------------------------------------------------------------------
    
        private var currentBitset:UintBitset = new UintBitset();
        
        private var states:Array = [];
        private var selectedFlags:Array = [];

        private function checkStates():void
        {
            var flags:Array /* of Uint */ = [];
            for (var i:int = 0; i < states.length; i++)
            {
                var state:uint = states[i].state;
                if (currentBitset.test(state))
                    flags.push(states[i]);
            }

            var index:int = 0;
            for (i = 0; i < selectedFlags.length; i++)
            {
                index = flags.indexOf(selectedFlags[i]);
                if (index == -1)
                {
                    DebugWrapper.log("DEBUG: f: " + String(new UintBitset(state)) + "\n         " + currentBitset);
                    selectedFlags[i].callback(false);
                }
            }

            for (i = 0; i < flags.length; i++)
            {
                index = selectedFlags.indexOf(flags[i]);
                if (index == -1)
                {
                    flags[i].callback(true);
                    DebugWrapper.log("DEBUG: t: " + String(new UintBitset(state)) + "\n         " + currentBitset);
                }
            }
            
            selectedFlags = flags;
        }
    
    }
}
